﻿using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;

namespace Common.Cache
{
    /// <summary>
    /// 本地内存缓存
    /// </summary>
    public class MemoryCache : ICache
    {
        private static readonly IMemoryCache Cache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new MemoryCacheOptions());
        private static MemoryCache _default;
        /// <summary>
        /// 内存缓存实例
        /// </summary>
        public static MemoryCache Instance
        {
            get
            {
                if (_default == null)
                {
                    _default = new MemoryCache();
                }
                return _default;
            }
        }

        private static List<string> AllKeys = new List<string>();

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiry">过期时间</param>
        /// <returns></returns>
        public bool Add(string key, object value, TimeSpan? expiry = null)
        {
            using (var entry = Cache.CreateEntry(key))
            {
                entry.Value = value;
                entry.AbsoluteExpirationRelativeToNow = expiry;
                entry.RegisterPostEvictionCallback((k, v, r, s) =>
                {
                    Debug.Write($"EvictionCallback has been triggered,k={k},v={v},r={r},s={s}");
                    if (r == EvictionReason.Expired || r == EvictionReason.Removed)
                    {
                        AllKeys.Remove(k.ToString());
                    }
                });
            }
            AllKeys.Add(key);
            return true;
        }
        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Delete(string key)
        {
            Cache.Remove(key);
            return true;
        }
        /// <summary>
        /// 判断缓存是否已存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Exist(string key)
        {
            Cache.TryGetValue(key, out object value);
            return value != null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            try
            {
                object value = GetObject(key);
                return (T)value;
            }
            catch
            {
                return default(T);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object GetObject(string key)
        {
            object value;
            Cache.TryGetValue(key, out value);
            return value;
        }

        /// <inheritdoc/>
        public T GetOrAdd<T>(string key, Func<string, T> func, TimeSpan? expiry = null)
        {
            Cache.TryGetValue(key, out object value);
            if (value is T valueOfT && valueOfT != null)
            {
                return valueOfT;
            }
            valueOfT = func(key);
            if (valueOfT != null)
            {
                Add(key, valueOfT, expiry);
            }
            return valueOfT;
        }
        /// <inheritdoc />
        public T GetOrAdd<T>(string key, Func<string, JCacheEntry<T>> func)
        {
            Cache.TryGetValue(key, out object value);
            if (value is T valueOfT && valueOfT != null)
            {
                return valueOfT;
            }
            valueOfT = default;
            var entry = func(key);
            if (entry != null && entry.Data != null)
            {
                valueOfT = entry.Data;
                Add(key, entry.Data, entry.Expiry);
            }
            return valueOfT;
        }
        /// <summary>
        /// 获取缓存字符串值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetString(string key)
        {
            object value;
            Cache.TryGetValue(key, out value);
            return value?.ToString();
        }
        /// <summary>
        /// 刷新缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public bool Refresh(string key, object value = null, TimeSpan? expiry = null)
        {
            Cache.Remove(key);
            if (value != null)
            {
                return Add(key, value, expiry);
            }
            return true;
        }
        /// <summary>
        /// 获取列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public List<T> GetList<T>(string pattern)
        {
            return Get<List<T>>(pattern);
        }
        /// <summary>
        /// 按通配符获取匹配的key
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public string[] GetKeys(string pattern)
        {
            pattern = pattern?.Replace("*", ".*");
            string[] array = AllKeys.ToArray();
            List<string> exist = new List<string>();
            foreach (var item in array)
            {
                if (Regex.IsMatch(item, $"^{pattern}$") && GetObject(item) != null)
                {
                    exist.Add(item);
                }
            }
            return exist.ToArray();
        }
    }
}
